/**
 *
 */
package com.shach.nutz.test.runner;

import com.shach.nutz.test.AbstractJUnit4NutzIocTests;
import com.shach.nutz.test.annoation.ModuleConfiguration;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.IocLoader;
import org.nutz.ioc.impl.NutIoc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.combo.ComboIocLoader;
import org.nutz.ioc.loader.json.JsonLoader;
import org.nutz.mvc.annotation.IocBy;
import org.nutz.mvc.ioc.provider.ComboIocProvider;
import org.nutz.mvc.ioc.provider.JsonIocProvider;

import java.lang.reflect.Field;
import java.lang.reflect.Method;


/**
 * Nutz Ioc 的 JUnit4 测试容器
 *
 * @author Shach
 * @email shacaihong@vip.qq.com
 */
public class NutzIocJUnit4ClassRunner extends BlockJUnit4ClassRunner {

    private Ioc ioc;

    public NutzIocJUnit4ClassRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    public void run(RunNotifier notifier) {
        try {
            initIoc();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        super.run(notifier);
    }

    protected void initIoc() throws Exception {
        Class<?> klass = getTestClass().getJavaClass();

        //必须集成AbstractJUnit4NutzIocTests
        if (!AbstractJUnit4NutzIocTests.class.isAssignableFrom(klass)) {
            throw new RuntimeException("Test type is invalid, not inherit AbstractJUnit4NutzIocTests.");
        }

        ModuleConfiguration moduleConfiguration = klass.getAnnotation(ModuleConfiguration.class);
        if (moduleConfiguration == null) {    //未正常配置Nutz模块类
            throw new RuntimeException("We haven't Nutz module configuration.");
        }

        Class<?> moduleKlass = moduleConfiguration.value();
        IocBy iocBy = moduleKlass.getAnnotation(IocBy.class);
        if (iocBy == null) {    //模块类不存在Ioc相关配置
            throw new RuntimeException("Nutz module is not @IocBy statement.");
        }

        IocLoader iocLoader = null;
        Class<?> iocType = iocBy.type();
        String[] args = iocBy.args();
        //初始化配置加载
        if (iocType == ComboIocProvider.class) {
            iocLoader = new ComboIocLoader(args);
        } else if (iocType == JsonIocProvider.class) {
            iocLoader = new JsonLoader(args);
        } else {
            throw new UnsupportedOperationException(String.format("Not support %s type of implementation.", iocType.getSimpleName()));
        }

        ioc = new NutIoc(iocLoader);
    }

    @Override
    protected Object createTest() throws Exception {
        Object testObj = super.createTest();
        Class<?> testObjClass = testObj.getClass();

        //注入Ioc容器（测试方法每次执行都会执行，测试用例中每个测试方法都是分开实例执行的）
        Method method = testObjClass.getMethod("setIoc", Ioc.class);
        if (method != null) {
            method.invoke(testObj, ioc);
        }

        //注入注解Bean
        for (Field field : testObjClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Inject.class)) {
                field.setAccessible(true);
                field.set(testObj, ioc.get(testObjClass));
            }
        }

        return testObj;
    }

    @Override
    protected Statement withBeforeClasses(Statement statement) {
        //XXX 静态变量赋值
        return super.withBeforeClasses(statement);
    }


}
